#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif

#import <errno.h>
#import <stdlib.h>
#import <string.h>

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <UIKit/UIFont.h>

#import "Application.h"

typedef enum
{
	UIStatusBarStyleDefault,
	UIStatusBarStyleBlackTranslucent,
	UIStatusBarStyleBlackOpaque
} UIStatusBarStyle;

typedef enum
{
	UIBarStyleDefault          = 0,
	UIBarStyleBlackOpaque      = 1,
	UIBarStyleBlackTranslucent = 2,
} UIBarStyle;

enum
{
	UIControlEventTouchDown           = 1 <<  0,
	UIControlEventTouchDownRepeat     = 1 <<  1,
	UIControlEventTouchDragInside     = 1 <<  2,
	UIControlEventTouchDragOutside    = 1 <<  3,
	UIControlEventTouchDragEnter      = 1 <<  4,
	UIControlEventTouchDragExit       = 1 <<  5,
	UIControlEventTouchUpInside       = 1 <<  6,
	UIControlEventTouchUpOutside      = 1 <<  7,
	UIControlEventTouchCancel         = 1 <<  8,
	
	UIControlEventValueChanged        = 1 << 12,
	
	UIControlEventEditingDidBegin     = 1 << 16,
	UIControlEventEditingChanged      = 1 << 17,
	UIControlEventEditingDidEnd       = 1 << 18,
	UIControlEventEditingDidEndOnExit = 1 << 19,
	
	UIControlEventAllTouchEvents      = 0x00000FFF,
	UIControlEventAllEditingEvents    = 0x000F0000,
	UIControlEventApplicationReserved = 0x0F000000,
	UIControlEventSystemReserved      = 0xF0000000,
	UIControlEventAllEvents           = 0xFFFFFFFF
};

typedef enum
{
	UITextFieldViewModeNever,
	UITextFieldViewModeWhileEditing,
	UITextFieldViewModeUnlessEditing,
	UITextFieldViewModeAlways
} UITextFieldViewMode;

typedef enum
{
	UIReturnKeyDefault,
	UIReturnKeyGo,
	UIReturnKeyGoogle,
	UIReturnKeyJoin,
	UIReturnKeyNext,
	UIReturnKeyRoute,
	UIReturnKeySearch,
	UIReturnKeySend,
	UIReturnKeyYahoo,
	UIReturnKeyDone,
	UIReturnKeyEmergencyCall,
} UIReturnKeyType;

typedef enum
{
	UIKeyboardTypeDefault,
	UIKeyboardTypeASCIICapable,
	UIKeyboardTypeNumbersAndPunctuation,
	UIKeyboardTypeURL,
	UIKeyboardTypeNumberPad,
	UIKeyboardTypePhonePad,
	UIKeyboardTypeNamePhonePad,
	UIKeyboardTypeEmailAddress,
} UIKeyboardType;

size_t strchcount(const char *s, char ch)
{
	size_t count;
	for (count = 0; *s; ++s)
		if (*s == ch)
			++count;
	return count;
}

@implementation Target

@synthesize name, mac;

- (id)initWithName:(NSString *)aName mac:(NSString *)aMac
{
	self = [super init];
	name = aName;
	mac = aMac;
	return self;
}

@end

@class UIScreen, UIColor;
@class UIActionSheet;
@class UISimpleTableCell;
@class UIAlertView;
@class UISimpleTableCell;

@implementation Application

@synthesize name, mac;

+ (void)initialize
{
	NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
	[defaultValues setValue:[NSNumber numberWithInt:0] forKey:@"target_count"];
	[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
	defaults = [NSUserDefaults standardUserDefaults];

	// socket
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(80);
	addr.sin_addr.s_addr = inet_addr("255.255.255.255");
	int so_broadcast = 1;
	setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so_broadcast, sizeof so_broadcast);
	
	// target array
	targets = [[NSMutableArray arrayWithCapacity: 1] retain];
	{
		int count = [defaults integerForKey:@"target_count"];
		for (int i = 0; i != count; ++i)
		{
			NSString *name = [defaults objectForKey:[NSString stringWithFormat:@"target_name_%02d", i]];
			NSString *mac = [defaults objectForKey:[NSString stringWithFormat:@"target_mac_%02d", i]];
			Target *target = [[Target alloc] initWithName:name mac:mac];
			[targets addObject:target];
		}
	}
	
	// frame rect
	CGRect frame = [[UIScreen mainScreen] bounds];
	frame.size.height -= 20;
	CGSize navBarSize = [UINavigationBar defaultSize];
	CGRect tableFrame = CGRectMake(0, frame.origin.y + navBarSize.height, frame.size.width, frame.size.height - navBarSize.height);
	CGRect tableSize = CGRectMake(0, frame.origin.y, frame.size.width, frame.size.height - navBarSize.height);
	
	// navigation bar
	navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0, 0, frame.size.width, navBarSize.height)];
	[navBar showButtonsWithLeftTitle:nil rightTitle:NSLocalizedString(@"Add", nil) leftBack:YES];
	[navBar setDelegate:self];	// NavigationBar delegate
	[navBar pushNavigationItem: [[UINavigationItem alloc] initWithTitle: NSLocalizedString(@"Target", nil)]];
	
	// target table
	targetTable = [[UITable alloc] initWithFrame:tableSize];
	[targetTable setDataSource:self];
	[targetTable setDelegate:self];
	[targetTable addTableColumn:nameColumn = [[UITableColumn alloc] initWithTitle: @"Name" identifier: @"name" width: frame.size.width * 1 / 3]];
	[targetTable addTableColumn:macColumn = [[UITableColumn alloc] initWithTitle: @"MAC" identifier: @"mac" width: frame.size.width * 2 / 3]];
	[targetTable reloadData];
	
	// edit view
	editTable = [[UIPreferencesTable alloc] initWithFrame:tableSize];
	[editTable setDelegate: self];
	[editTable setDataSource: self];
	[editTable reloadData];
	
	// table row items
	name = [[UIPreferencesTextTableCell alloc] init];
	[name setTitle:NSLocalizedString(@"Name", nil)];
	[[name textField] setEnabled:YES];
	[[name textField] setClearButtonMode:UITextFieldViewModeAlways];
	[[name textField] setReturnKeyType:UIReturnKeyNext];
	[[name textField] setDelegate:self];
	
	mac = [[UIPreferencesTextTableCell alloc] init];
	[mac setTitle:NSLocalizedString(@"MAC Address", nil)];
	[[mac textField] setEnabled:YES];
	[[mac textField] setPlaceholder:@"ff:ff:ff:ff:ff:ff"];
	[[mac textField] setClearButtonMode:UITextFieldViewModeAlways];
	[[mac textField] setReturnKeyType:UIReturnKeyDone];
	[[mac textField] setDelegate:self];
	
	// transition view
	view = [[UITransitionView alloc] initWithFrame:tableFrame];
	
	// whole view
	wholeView = [[UIView alloc] initWithFrame:frame];
	[wholeView setBackgroundColor:[UIColor whiteColor]];
	[wholeView addSubview:navBar];
	[wholeView addSubview:view];
	
	// create window and show
	frame.origin.y = 20;
	window = [[UIWindow alloc] initWithFrame:frame];
	[window setContentView:wholeView];
	[window makeKeyAndVisible];
	
	// set table view
	[view transition:0 toView:targetTable];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
	close(socket);
	
	[defaults setInteger:[targets count] forKey:@"target_count"];
	for (int i = 0; i != [targets count]; ++i)
	{
		[defaults setObject:[[targets objectAtIndex:i] name] forKey:[NSString stringWithFormat:@"target_name_%02d", i]];
		[defaults setObject:[[targets objectAtIndex:i] mac] forKey:[NSString stringWithFormat:@"target_mac_%02d", i]];
	}
}

- (void)dealloc
{
	[window release];
	[view release];
	[targetTable release];
	[navBar release];
	[editTable release];
	
	[super dealloc];
}


- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
	if (textField == [name textField])
		[[mac textField] becomeFirstResponder];
	else if (textField == [mac textField])
		[[mac textField] resignFirstResponder];
	
	return YES;
}

- (void)reloadData
{
	[editTable reloadData];
}

// data sources
- (int)numberOfGroupsInPreferencesTable:(UIPreferencesTable *)table
{
	return 1;
}

- (int)preferencesTable:(UIPreferencesTable *)table numberOfRowsInGroup:(int)group
{
	return 2;
}

- (NSString *)preferencesTable:(UIPreferencesTable *)table titleForGroup:(int)group
{
	return @"Target";
}

- (UIPreferencesTableCell *)preferencesTable:(UIPreferencesTable *)table cellForRow:(int)row inGroup:(int)group
{
	switch (row)
	{
		case 0:	return name;
		case 1:	return mac;
	}
}

- (void)navigationBar:(UINavigationBar*)navigationBar buttonClicked:(int)button
{
	if ([[[navBar topItem] title] isEqualToString:@"Edit"])
	{
		NSString *nameStr = [name value];
		NSString *macStr = [mac value];
		if ([nameStr length] == 0 || [macStr length] == 0 || (12 + 5) < [macStr length])
			return;
		if (strchcount([[mac value] cStringUsingEncoding:NSASCIIStringEncoding], ':') != 5)
			return;
		
		Target *target = [[Target alloc] initWithName:[nameStr copy] mac:[macStr copy]];
		[targets addObject:target];
		[targetTable reloadData];
		
		[navBar popNavigationItemAnimated:YES];
		[navBar showButtonsWithLeftTitle:nil rightTitle:NSLocalizedString(@"New", nil)];
	}
	else
	{
		[view transition:1 toView:editTable];
		[navBar pushNavigationItem:[[UINavigationItem alloc] initWithTitle:NSLocalizedString(@"Edit", nil)]];
		[navBar showButtonsWithLeftTitle:nil rightTitle:NSLocalizedString(@"Done", nil)];
		[name setValue:@""];
		[mac setValue:@""];
	}
}

- (void)navigationBar:(UINavigationBar *)navigationBar poppedItem:(UINavigationItem *)item
{
	[navBar showButtonsWithLeftTitle: nil rightTitle:NSLocalizedString(@"New", nil)];
	[view transition:2 toView:targetTable];
}

// tables
- (int)numberOfRowsInTable:(UITable*)table
{
	return [targets count];
}

- (UITableCell*)table:(UITable*)table cellForRow:(int)row column:(UITableColumn *)column
{
	UISimpleTableCell *cell = [[UISimpleTableCell alloc] init];
	if (0 <= row && row < [targets count])
	{
		if (column == nameColumn)
			[cell setTitle:[[targets objectAtIndex:row] name]];
		else if (column == macColumn)
			[cell setTitle:[[targets objectAtIndex:row] mac]];
	}
	return [cell autorelease];
}

/*
	swipe to delete
	http://idevdocs.com/forum/showthread.php?t=78&highlight=UITable
*/
- (void)table:(UITable *)table willSwipeToDeleteRow:(int)row
{
	if (0 <= row && row < [targets count])
		[targetTable setDeleteConfirmationRow:row];
}


- (BOOL)table:(UITable *)table canDeleteRow:(int)row
{
	if (0 <= row && row < [targets count])	return YES;
	return NO;
}

- (void)table:(UITable *)table deleteRow:(int)row 
{
	if (0 <= row && row < [targets count])
		[targets removeObjectAtIndex:row];
}

// delegates
- (void)tableRowSelected:(NSNotification *)notification
{
	id sender = [notification object];
	int row = [sender selectedRow];
	
	if (!(0 <= row && row < [targets count]))	return;
	
	char mac[12 + 5 + 1];
	strcpy(mac, [[[targets objectAtIndex:row] mac] cStringUsingEncoding:NSASCIIStringEncoding]);
	
	unsigned char macAddr[6];
	const char *hex = strtok(mac, ":");
	for (size_t i = 0; i != sizeof macAddr / sizeof macAddr[0] && hex != NULL; ++i)
	{
		sscanf(hex, "%x", &(macAddr[i]));
		hex = strtok(NULL, ":");
	}
	
	unsigned char packet[6 + (6 * 16)];
	memset(packet, 0xff, 6);
	for (int i = 0; i != 16; ++i)
		memcpy(packet + (6 * i) + 6, macAddr, sizeof macAddr);
	
/*
	for (size_t i = 0; i != sizeof packet; i += 6)
		NSLog(@"%02x %02x %02x %02x %02x %02x", packet[i], packet[i + 1], packet[i + 2], packet[i + 3], packet[i + 4], packet[i + 5]);
*/
	
	sendto(sock, packet, sizeof packet, 0, (struct sockaddr *)&addr, sizeof(addr));
}

@end
